#include "RleManager.h"

RleManager::RleManager(FILE *file, Header &header) : file(file)
{
}

RleManager::~RleManager()
{
}

void RleManager::WriteHeader(Header &header)
{
    fwrite(&header, sizeof(Header), 1,  file);
}

void RleManager::ReadHeader()
{
    fread(&this->header, sizeof(Header),1, file);
}

Header &RleManager::GetHeader()
{
    return this->header;
}

bool RleManager::ReadBlock(int *buffer)
{
    return true;
}

bool RleManager::WriteBlockLuminance(int *block)
{
    this->RleEncodeLuminance(block);
    return true;
}

bool RleManager::WriteBlockCrominance(int *block)
{
    this->RleEncodeCrominance(block);
    return true;
}

static int countWrite = 0;
static int countRead = 0;

void RleManager::RleEncodeLuminance(int *block)
{
    int total = 0;
    short count = 0;
    short buffer[100];

    for (int i = 0; i < 64; ++i)
    {
        if (block[i] != 0)
        {
            if (count > 0)
            {
                short zero = 0;
                buffer[total] = zero;
                total += 1;
                buffer[total] = count;
                total += 1;
                count = 0;
            }
            /*			if (block[i] > 127 && i != 0)
                    block[i] = 127;
            if (block[i] < -127 && i != 0)
                block[i] = -127;*/
            buffer[total] = block[i];
            total += 1;
        }
        else
            count += 1;
    }
    if (count > 0)
    {
        short zero = 0;
        buffer[total] = zero;
        total += 1;
        buffer[total] = count;
        total += 1;
    }
    countWrite += fwrite(buffer, sizeof(short), total , file);
}

void DisplayTab3(int *tab)
{
    std::cout << std::endl;
    for (int i = 0; i < 64; ++i)
    {
        if (i % 8 == 0)
            std::cout << std::endl;
        std::cout << tab[i] << " ";
    }
    std::cout << std::endl;
}

void RleManager::RleEncodeCrominance(int *block)
{
    int total = 0;
    signed char buffer[100];
    uchar count = 0;

    countWrite += fwrite(&block[0], sizeof(short), 1, file);
    for (int i = 1; i < 64; ++i)
    {
        if (block[i] != 0)
        {
            if (count > 0)
            {
                uchar zero = 0;
                buffer[total] = zero;
                total += 1;
                buffer[total] = count;
                total += 1;
                count = 0;
            }
            if (block[i] > 127)
            {
                DisplayTab3(block);
                block[i] = 127;
            }
            buffer[total] = block[i];
            total += 1;
        }
        else
            count += 1;
    }
    if (count > 0)
    {
        uchar zero = 0;
        buffer[total] = zero;
        total += 1;
        buffer[total] = count;
        total += 1;
    }
    countWrite += fwrite(buffer, sizeof(signed char), total , file);
}

void RleManager::GetNextBlock(int *buffer)
{
    short bufferShort = 0;
    signed char bufferChar;
    int count = 1;
    int read = 0;
    fread(&bufferShort, sizeof(short), 1, this->file);
    buffer[0] = bufferShort;
    while (count < 64)
    {
        fread(&bufferChar, sizeof(signed char), 1, this->file);
        if (bufferChar == 0)
        {
            read += fread(&bufferChar, sizeof(signed char), 1, this->file);
            for (int i = 0; i < bufferChar; ++i)
            {
                buffer[count] = 0;
                count += 1;
            }
        }
        else
        {
            buffer[count] = bufferChar;
            count += 1;
        }
    }
}

void RleManager::GetNextBlockLuminance(int *buffer)
{
    short bufferShort = -1;
    int count = 1;

    countRead += fread(&bufferShort, sizeof(short), 1, this->file);

    buffer[0] = bufferShort;
    while (count < 64)
    {
        countRead += fread(&bufferShort, sizeof(short), 1, this->file);

        if (bufferShort == 0)
        {
            countRead += fread(&bufferShort, sizeof(short), 1, this->file);
            for (int i = 0; i < bufferShort; ++i)
            {
                buffer[count] = 0;
                count += 1;
            }
        }
        else
        {
            buffer[count] = bufferShort;
            count += 1;
        }
    }
}

DCT_ENCODED *RleManager::RleDecode()
{
    int bufferRed[64];
    int bufferBlue[64];
    int bufferLum[64];
    short bufferShort;
    signed char bufferChar;


    DCT_ENCODED *DctTable = new DCT_ENCODED(header.height, header.width);

    int size = (header.height * header.width) / 4;
    int nbBlock = size / 64;
    int widthBlock = header.width / 8;
    int heightBlock = header.height / 8;

    int heigh = heightBlock /2;
    int width = widthBlock /2;
    for (int i = 0 ; i < heigh; ++i)
    {
        for (int j = 0 ; j < width; ++j)
        {
            //Blue
            GetNextBlock(bufferBlue);

            //Red
            GetNextBlock(bufferRed);

            for(int z = 0; z < 64; ++z)
            {
                int h = i * 8 + z / 8;
                int w = j * 8 + z % 8;
                cv::Vec2i vec(bufferBlue[z], bufferRed[z]);

                DctTable->tabChrominance[h][w] = vec;

            }
        }
    }
    for (int count = 0; count < nbBlock * 4; ++count)
    {
        //Luminance
        GetNextBlockLuminance(bufferLum);
        for(int i = 0; i  < 64; ++i)
        {
            DctTable->luminance[i + (count * 64)] = bufferLum[i];
        }
    }
    return DctTable;
}
